package br.uefs.dexa.rfframework.gui.utils.paging;

import java.awt.Container;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.swing.BoxLayout;

import br.uefs.dexa.rfframework.config.AppConfigManager;
import br.uefs.dexa.rfframework.gui.factory.GUIAbstractFactory;
import br.uefs.dexa.rfframework.gui.interfaces.DigitalObjectPanel;
import br.uefs.dexa.rfframework.gui.interfaces.OutputObjectSetContainerPanel;
import br.uefs.dexa.rfframework.gui.interfaces.RFUserGUI;
import br.unicamp.ic.lis.rfframework.objects.DigitalObject;
import br.unicamp.ic.lis.rfframework.objects.DigitalObjectSet;
import br.unicamp.ic.lis.rfframework.objects.IDigitalObject;
import br.unicamp.ic.lis.rfframework.objects.exceptions.EmptyCollectionException;
import br.unicamp.ic.lis.rfframework.objects.exceptions.ObjectNotFoundException;

public class PagingOutputObjectSetContainerPanel extends OutputObjectSetContainerPanel {

	
	

	private static final long serialVersionUID = -6579528479807053309L;
	
	public static final float PAGE_LABEL_FONT_SIZE = 24.0f;
	
	private OutputObjectSetContainerPanel core;
	
	private PagingControlPanel pagingControlPanel;
	
	private DigitalObjectSet<DigitalObject> objects;
	
	private List<Long> selectedObjects;
	
	private int currentPage = 1;
	
	
	private int begin = 0;
	
	private int end = AppConfigManager.getInstance().getMaxItensPerPage() - 1;
	
	private Mode currentMode = Mode.NONE;
	
	private enum Mode 
	{ 
		NONE, QUERY, RELEVANT
	}

	
	public PagingOutputObjectSetContainerPanel (OutputObjectSetContainerPanel core)
	{
		super(null);
		this.core = core;
		build();
	}
	
	@Override
	public void compose() 
	{
		//empty
	}

	private void build()
	{
		setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));		
		pagingControlPanel = new PagingControlPanel(this);
		add(pagingControlPanel);
		add(core);
	}
	
	@Override
	public void beforeQuerySelection()
	{
		core.beforeQuerySelection();
	}

	@Override
	public void querySelectionMode()
	{
		core.querySelectionMode();
		currentMode = Mode.QUERY;
	}
	
	@Override
	public void afterQuerySelection()
	{
		core.afterQuerySelection();
	}
	
	@Override
	public void beforeRelevanceFeedback()
	{
		core.beforeQuerySelection();
	}
	
	@Override
	public void relevanceFeedbackMode()
	{
		core.relevanceFeedbackMode();
		currentMode = Mode.RELEVANT;
	}
	
	@Override
	public void afterRelevanceFeedback()
	{
		core.afterRelevanceFeedback();
	}

	
	@Override
	public void showObjectPanel(DigitalObjectPanel panel)
	{
		core.showObjectPanel(panel);
	}
	
	@Override
	public void removeObjectPanel(DigitalObjectPanel panel)
	{
		core.removeObjectPanel(panel);
	}
	
	@Override
	public  DigitalObjectPanel getDigitalObjectPanel(IDigitalObject object)
	{
		return core.getDigitalObjectPanel(object);
	}
	
	@Override
	public void neutralMode()
	{
		core.neutralMode();
		currentMode = Mode.NONE;
	}
	
	
	private void startCorrectMode()
	{
		switch (currentMode) 
		{
			case QUERY:
				core.querySelectionMode();
				break;
			case RELEVANT:
				core.relevanceFeedbackMode();
				break;
			case NONE:
				core.neutralMode();
				break;
			default:
				break;

		}
	}
	
	
	@Override
	public void resetSelected(IDigitalObject object)
	{
		core.resetSelected(object);
	}
	
	@Override
	public void showObjects(DigitalObjectSet<DigitalObject> objects)
	{
		this.objects = objects;
		int page = 1;
		selectedObjects = new ArrayList<Long>();
		
		setLimits(page);
				
		pagingControlPanel.setVisible(false);
		pagingControlPanel.generateLabels(objects);
		pagingControlPanel.addLabels();
		pagingControlPanel.markCurrentPageLabel(page);
		
		if(objects.getSize() > AppConfigManager.getInstance().getMaxItensPerPage())
		{
			pagingControlPanel.setVisible(true);
			showPage();
			
		} else {
			
			core.showObjects(objects);
		}
	}
	
	@Override
	public void startLoadingProgressViewer(int min, int max)
	{
		core.startLoadingProgressViewer(min, max);
	}
	
	@Override
	public void updateLoadingProgressViewer(int progress)
	{
		core.updateLoadingProgressViewer(progress);
	}
	
	@Override
	public void finalizeLoadingProgressViewer()
	{
		core.finalizeLoadingProgressViewer();
	}
	
	public boolean isLastPage(int page)
	{
		int noPages =  ( objects.getSize() / AppConfigManager.getInstance().getMaxItensPerPage() ) + 1;
		return noPages == page;
	}
	
	protected void previousPage()
	{
		if(currentPage > 1) {
			setLimits(currentPage - 1);
//			resetLabels();
//			showPage();
		}
	}
	
	protected void nextPage()
	{
		if(!isLastPage(currentPage)) {
			setLimits(currentPage + 1);
//			resetLabels();
//			showPage();
		}
	}

	protected void setLimits(int page)
	{
		currentPage = page;
		int maxItensPerPage = AppConfigManager.getInstance().getMaxItensPerPage();
		
		if (isLastPage(page)) {
			end = ((maxItensPerPage * (page-1)) - 1) + ( objects.getSize() % maxItensPerPage );
			begin = end - ( objects.getSize() % maxItensPerPage ) + 1;
			
		} else {
			end = (maxItensPerPage * page) - 1;
			begin = end - maxItensPerPage + 1;
		}
	}
	
	protected void resetLabels()
	{
		pagingControlPanel.resetLabels();
	}
	
	protected void markCurrentPage()
	{
		pagingControlPanel.markCurrentPageLabel(currentPage);
	}

	
	protected void showPage()
	{
		DigitalObjectSet<DigitalObject> pageCache = new DigitalObjectSet<DigitalObject>();
		saveSelectedObjects();
	
		pagingControlPanel.showOnlyNeighborLabels(currentPage);
		pagingControlPanel.setVisible(true);
		pagingControlPanel.disableLabels();
		
		for (int i = begin; i < end; i++) {
			
			IDigitalObject object = null;
			
			try {
				
				object = objects.getObjectByIndex(i);
				
			} catch (ObjectNotFoundException | EmptyCollectionException e) {
				
				break;
			}
			
			pageCache.addObject( (DigitalObject) object);
		}
		
		core.showObjects(pageCache);
		//setSelectedObjects();
		startCorrectMode();
		setSelectedObjects();
		pagingControlPanel.enableLabels();

	}
	
	private void saveSelectedObjects()
	{
		Map<Long, DigitalObjectPanel> panels = core.getPanels();
		
		for (DigitalObjectPanel panel : panels.values()) 
		{
		    if(panel.isSelected()) {
		    	if(!selectedObjects.contains(panel.getObjectId()))
		    		selectedObjects.add(panel.getObjectId());
		    } else {
		    	if(selectedObjects.contains(panel.getObjectId()))
		    		selectedObjects.remove(panel.getObjectId());
		    }
		}
	}
	
	private void setSelectedObjects()
	{
		Map<Long, DigitalObjectPanel> panels = core.getPanels();
		
		for (DigitalObjectPanel panel : panels.values()) 
		{
			if(selectedObjects.contains(panel.getObjectId()))
				panel.setSelected(true);
		}
	}
	
	
	
	@Override
	public Container getOuputObjectsContainer() 
	{
		//return this;
		return core.getOuputObjectsContainer();
	}

	

}
